package simulator.software.scheduling;

import java.util.Collections;
import java.util.Comparator;
import java.util.Iterator;
import java.util.List;
import java.util.Vector;

import simulator.software.Process;
import simulator.software.ProcessState;

/**
 * Implementation of a priority scheduling algorithm. Processes are given
 * preference for selection based on priority.
 * 
 * @author David LaPointe
 * 
 */
public class PriorityScheduler implements Scheduler
{
   public String getDescription()
   {
      return "Priority Scheduler";
   }

   public Process nextProcess(List<Process> processTable)
   {
      boolean reset = true;

      System.out.println("Priority scheduler called.  Current state: ");

      for (Process p : processTable)
      {
         System.out.println(p.getName() + "(" + p.getStatusDescriptor() + "): "
               + p.getAdjustedPriority() + "/" + p.getPriority());
      }

      for (Process p : processTable)
      {
         if (p.getAdjustedPriority() > 0)
         {
            reset = false;
            break;
         }
      }

      if (reset)
      {
         // reset priorities
         for (Process p : processTable)
         {
            p.setAdjustedPriority(p.getPriority());
         }
      }

      // build list of processes ready to run
      List<Process> readyProcesses = new Vector<Process>();

      for (Process p : processTable)
      {
         if (p.getState() == ProcessState.READY)
         {
            readyProcesses.add(p);
         }
      }

      if (readyProcesses.size() == 0)
      {
         // no processes are ready to run
         return null;
      }

      // sort processes by adjusted priority
      Collections.sort(readyProcesses, new AdjustedPriorityComparator());

      // build list of processes with the highest adjusted priority
      int highestPriority = readyProcesses.get(0).getAdjustedPriority();

      for (Iterator<Process> i = readyProcesses.iterator(); i.hasNext();)
      {
         Process p = i.next();

         if (p.getAdjustedPriority() != highestPriority)
         {
            i.remove();
         }
      }

      // sort processes with same adjusted priority by initial priority
      Collections.sort(readyProcesses, new PriorityComparator());

      Process nextProcess = readyProcesses.get(0);

      // decrement the selected process's priority
      nextProcess.setAdjustedPriority(nextProcess.getAdjustedPriority() - 1);

      return nextProcess;
   }

   protected class AdjustedPriorityComparator implements Comparator<Process>
   {
      public int compare(Process p1, Process p2)
      {
         return new Integer(p2.getAdjustedPriority()).compareTo(p1
               .getAdjustedPriority());
      }
   }

   protected class PriorityComparator implements Comparator<Process>
   {
      public int compare(Process p1, Process p2)
      {
         return new Integer(p2.getPriority()).compareTo(p1.getPriority());
      }
   }
}
